﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic;
using DiscoveryLogic.Analytics.BusinessLogic.Dedups;
using DiscoveryLogic.Analytics.BusinessLogic.Measures;
using DiscoveryLogic.Analytics.BusinessLogic.Rules;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Dedup;
using DiscoveryLogic.Analytics.DataObjects.Filters;
using DiscoveryLogic.Analytics.DataObjects.Measures;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Analytics.DataObjects.Visuals;
using DiscoveryLogic.Analytics.Diagrams.NetworkGraphs;
using DiscoveryLogic.Analytics.Modules;
using DiscoveryLogic.Analytics.Modules.DedupRules;
using DiscoveryLogic.Analytics.Modules.Explorers;
using DiscoveryLogic.Analytics.Modules.Filters;
using DiscoveryLogic.Analytics.Modules.LinkRules;
using DiscoveryLogic.Analytics.Modules.Nodes;
using DiscoveryLogic.Analytics.Modules.VisualSettings;
using DiscoveryLogic.Analytics.UI.Common.Events;
using DiscoveryLogic.Analytics.UI.Common.Wizard;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.Diagrams.RadialGraphs
{
    /// <summary>
    /// Interaction logic for RadialGraphView.xaml
    /// </summary>
    public partial class RadialGraphView : UserControl
    {
        #region events

        public delegate void OnEntitySelected(EntityBase entity);

        public event OnEntitySelected EntitySelected;
        #endregion

        #region fields
        private RadialGraphPresenter _Presenter;
        #endregion

        #region ctor
        public RadialGraphView()
        {
            InitializeComponent();
        }

        public RadialGraphView(RadialGraphPresenter presenter)
            :this()
        {
            this._Presenter = presenter;
            this._Presenter.View = this;
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {

        }
        #endregion

        #region render
        public void InitializeGraphObjects(Network network)
        {
            List<VerticeMeasure> verticeMeasures = NetworkMeasureManager.GetVerticeMeasures(network.NetworkName);
            Dictionary<EntityType, Dictionary<string, VerticeMeasure>> measures =
                NetworkMeasureManager.ToDictionary(verticeMeasures);
            VerticeMeasureRange range = NetworkMeasureManager.GetMeasureRanges(verticeMeasures);
            NetworkVisual netVisual = NetworkVisual.Read(network.NetworkName);
            
            this.radialGraph.Children.Clear();
            // List<PersonDO> persons = EntityManager.GeneratePersonsForTest();
            List<Vertice> vertices = new List<Vertice>();
            List<Edge> edges = new List<Edge>();
            int w = (int)this.radialGraph.ActualWidth;
            int h = (int)this.radialGraph.ActualHeight;
            Random randGen = new Random(DateTime.Now.Second);
            Dictionary<string, Guid> personVerticeMappings = new Dictionary<string, Guid>();
            Dictionary<string, Guid> grantVerticeMappings = new Dictionary<string, Guid>();
            Dictionary<string, Guid> pubVerticeMappings = new Dictionary<string, Guid>();
            Dictionary<string, Guid> orgVerticeMappings = new Dictionary<string, Guid>();
            foreach (EntityBase entity in network.Records)
            {
                Vertice v = new Vertice(Guid.NewGuid(), entity.Name);
                v.Tag = entity;
                v.Control = this.CreateEntityControl(entity, netVisual, measures[entity.EntityType][entity.PKValue()],
                                                     range);
                v.Position = new Vector(randGen.Next(w), randGen.Next(h));
                vertices.Add(v);
                if (entity is PersonDO && !personVerticeMappings.ContainsKey(entity.PKValue()))
                    personVerticeMappings.Add(entity.PKValue(), v.ID);
                else if (entity is ExternalOrgDO && !orgVerticeMappings.ContainsKey(entity.PKValue()))
                    orgVerticeMappings.Add(entity.PKValue(), v.ID);
                else if (entity is PublicationDO && !pubVerticeMappings.ContainsKey(entity.PKValue()))
                    pubVerticeMappings.Add(entity.PKValue(), v.ID);
                else if (entity is GrantDO && !grantVerticeMappings.ContainsKey(entity.PKValue()))
                    grantVerticeMappings.Add(entity.PKValue(), v.ID);
            }
            foreach (Link link in network.Links)
            {
                Guid fromID = Guid.Empty;
                Guid toID = Guid.Empty;
                if (link.FromType == typeof(GrantDO) &&
                    grantVerticeMappings.ContainsKey(link.FromKey))
                    fromID = grantVerticeMappings[link.FromKey];
                else if (link.FromType == typeof(ExternalOrgDO) &&
                    orgVerticeMappings.ContainsKey(link.FromKey))
                    fromID = orgVerticeMappings[link.FromKey];
                else if (link.FromType == typeof(PersonDO) &&
                    personVerticeMappings.ContainsKey(link.FromKey))
                    fromID = personVerticeMappings[link.FromKey];
                else if (link.FromType == typeof(PublicationDO) &&
                    pubVerticeMappings.ContainsKey(link.FromKey))
                    fromID = pubVerticeMappings[link.FromKey];

                if (link.ToType == typeof(GrantDO) &&
                    grantVerticeMappings.ContainsKey(link.ToKey))
                    toID = grantVerticeMappings[link.ToKey];
                if (link.ToType == typeof(ExternalOrgDO) &&
                    orgVerticeMappings.ContainsKey(link.ToKey))
                    toID = orgVerticeMappings[link.ToKey];
                else if (link.ToType == typeof(PersonDO) &&
                    personVerticeMappings.ContainsKey(link.ToKey))
                    toID = personVerticeMappings[link.ToKey];
                else if (link.ToType == typeof(PublicationDO) &&
                    pubVerticeMappings.ContainsKey(link.ToKey))
                    toID = pubVerticeMappings[link.ToKey];

                if (fromID != Guid.Empty && toID != Guid.Empty)
                {
                    if (link.Directional)
                    {
                        Arc e = new Arc(
                            Guid.NewGuid(),
                            link.Distance.ToString(), link.Distance,
                            fromID, toID);
                        edges.Add(e);
                    }
                    else
                    {
                        Edge e = new Edge(
                            Guid.NewGuid(),
                            link.Distance.ToString(), link.Distance,
                            fromID, toID);
                        edges.Add(e);
                    }
                }
            }

            this.radialGraph.NetworkName = network.NetworkName;
            this.radialGraph.NetVisual = netVisual;
            NetworkExclusionSetting exSetting = NetworkExclusionSetting.Read(network.NetworkName);
            this.radialGraph.ExSetting = exSetting;
            NetworkInclusionSetting inSetting = NetworkInclusionSetting.Read(network.NetworkName);
            this.radialGraph.InSetting = inSetting;
            this.radialGraph.Vertices = vertices;
            this.radialGraph.Edges = edges;
            this.radialGraph.StartSimulation();
        }

        private EntityControlBase CreateEntityControl(
            EntityBase entity, NetworkVisual visual, 
            VerticeMeasure measure, VerticeMeasureRange range)
        {
            EntityControlBase entityView = null;
            switch (entity.EntityType)
            {
                case EntityType.Persons:
                    entityView = new PersonNode(entity,
                        visual.EntityVisuals[EntityType.Persons],
                        false, measure, range);
                    ((PersonNode)entityView).ExploreSelectedEntity += new OnExploreSelectedEntity(HandleExploreSelectedEntity);
                    ((PersonNode)entityView).DefineNewRelation +=
                        new OnDefineNewRelationRuleFromNetworkEntity(HandleRuleDefinitionFromEntity);
                    break;
                case EntityType.Publications:
                    entityView = new PubNode(entity,
                        visual.EntityVisuals[EntityType.Publications],
                        false, measure, range);
                    ((PubNode)entityView).ExploreSelectedEntity += new OnExploreSelectedEntity(HandleExploreSelectedEntity);
                    ((PubNode)entityView).DefineNewRelation +=
                        new OnDefineNewRelationRuleFromNetworkEntity(HandleRuleDefinitionFromEntity);
                    break;
                case EntityType.Grants:
                    entityView = new GrantNode(entity, visual.EntityVisuals[EntityType.Grants],false,measure,range);
                    ((GrantNode)entityView).ExploreSelectedEntity += new OnExploreSelectedEntity(HandleExploreSelectedEntity);
                    ((GrantNode)entityView).DefineNewRelation +=
                        new OnDefineNewRelationRuleFromNetworkEntity(HandleRuleDefinitionFromEntity);
                    break;
                case EntityType.Organizations:
                    entityView = new OrgNode(entity,
                        visual.EntityVisuals[EntityType.Organizations],
                        false, measure, range);
                    ((OrgNode)entityView).ExploreSelectedEntity += new OnExploreSelectedEntity(HandleExploreSelectedEntity);
                    ((OrgNode)entityView).DefineNewRelation +=
                        new OnDefineNewRelationRuleFromNetworkEntity(HandleRuleDefinitionFromEntity);
                    break;
            }
            entityView.DataContext = entity;
            this.radialGraph.Children.Add(entityView);

            entityView.MouseEnter += new MouseEventHandler(this.radialGraph.Canvas_MouseEnter);
            entityView.MouseDown += new MouseButtonEventHandler(this.radialGraph.Canvas_MouseDown);
            entityView.MouseMove += new MouseEventHandler(this.radialGraph.Canvas_MouseMove);
            entityView.MouseUp += new MouseButtonEventHandler(this.radialGraph.Canvas_MouseUp);

            return entityView;
        }

        private void HandleExploreSelectedEntity(ExploreEntityEventArgs args)
        {
            if(!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                Network network = Network.Read(this.radialGraph.NetworkName);
                
                ExploreSelectedEntity explorer = new ExploreSelectedEntity(network, args.SrcEntity, args.TgtEntityType);
                PopupWindow dialog=new PopupWindow();
                dialog.Content = explorer;
                dialog.Show();
            }
        }

        private void HandleRuleDefinitionFromEntity(NewRuleFromNetworkEntityArgs args)
        {
            List<IWizardPageBase> wizPages = new List<IWizardPageBase>();
            LinkRuleNetworkSelectedEntity page1 = new LinkRuleNetworkSelectedEntity();
            LinkRuleSqlParameters page2 = new LinkRuleSqlParameters();
            LinkRuleTgtEntityFieldMappings page3 = new LinkRuleTgtEntityFieldMappings();
            LinkRuleDistanceCalculator page4 = new LinkRuleDistanceCalculator();

            page1.PrevPage = null;
            page1.NextPage = page2;

            page2.PrevPage = page1;
            page2.NextPage = page3;

            page3.PrevPage = page2;
            page3.NextPage = page4;

            page4.PrevPage = page3;
            page4.NextPage = null;

            wizPages.Add(page1);
            wizPages.Add(page2);
            wizPages.Add(page3);
            wizPages.Add(page4);
            EntityRelationRule rule =
                new EntityRelationRule(
                    "Link Rule", "/images/rule.png",
                    this.radialGraph.NetworkName,
                    args.Entity.EntityType, 
                    EntityType.Grants,
                    args.Entity.PKValue());
            rule.SrcEntityType = args.Entity.EntityType;
            Dictionary<string, object> sharedVars = new Dictionary<string, object>();
            sharedVars.Add("LinkRule", rule);
            Wizard wiz = new Wizard(sharedVars, wizPages.ToArray(), page1);
            wiz.Finish += new Wizard.OnFinish(wizLinkRule_Finish);
            wiz.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            wiz.Show();
        }

        private void wizLinkRule_Finish(Dictionary<string, object> sharedVars)
        {
            EntityRelationRule rule = (EntityRelationRule)sharedVars["LinkRule"];
            
            RuleManager.Save(rule);
            MyData.ReadAllRules();
        }

        public void SubscribeViewGraphEventHandler(Network network)
        {
            this._Presenter.RegisterViewGraphEventHandler(network);
        }
        #endregion

        #region selection
        private void radialGraph_VerticeSelected(Vertice v)
        {
            if (v != null && v.Tag != null && this.EntitySelected != null)
            {
                this.EntitySelected(v.Tag);
            }
        }

        public void SelectEntity(EntityBase entity)
        {
            this.radialGraph.SelectEntity(entity);
        }

        public void SubscribeEventHandler(EntityBase entity)
        {
            this._Presenter.UpdateViewSelection(entity);
        }
        #endregion

        #region redraw
        private void mnuRedraw_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                Network network = Network.Read(this.radialGraph.NetworkName);
                this.InitializeGraphObjects(network);
                //NetworkVisual netVisual = NetworkVisual.Read(this.radialGraph.NetworkName);
                //this.radialGraph.NetVisual = netVisual;
                //NetworkExclusionSetting exSetting = NetworkExclusionSetting.Read(this.radialGraph.NetworkName);
                //this.radialGraph.ExSetting = exSetting;
                //NetworkInclusionSetting inSetting = NetworkInclusionSetting.Read(this.radialGraph.NetworkName);
                //this.radialGraph.InSetting = inSetting;
                //this.radialGraph.StartSimulation();
            }
        }

        private void UpdateNetworkGraph(Network network)
        {
            this.InitializeGraphObjects(network);
        }
        #endregion

        #region visual
        private void mnuVerticeVisual_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName) &&
                this.radialGraph.Vertices != null &&
                this.radialGraph.Vertices.Count > 0)
            {
                PopupWindow dialog = new PopupWindow();
                dialog.WindowStyle = WindowStyle.None;
                VerticeVisualSetting visualSetting = new VerticeVisualSetting(this.radialGraph.NetworkName);
                dialog.Content = visualSetting;
                dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                dialog.ShowDialog();
            }
        }

        private void mnuEdgeVisual_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName) &&
                this.radialGraph.Vertices != null &&
                this.radialGraph.Vertices.Count > 0)
            {
                PopupWindow dialog = new PopupWindow();
                dialog.WindowStyle = WindowStyle.None;
                EdgeVisualSetting visualSetting = new EdgeVisualSetting(this.radialGraph.NetworkName);
                dialog.Content = visualSetting;
                dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                dialog.ShowDialog();
            }
        }
        #endregion

        #region filter
        private void mnuExclude_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                NetworkEntityExcludeSetting exSetting = new NetworkEntityExcludeSetting(this.radialGraph.NetworkName);
                exSetting.NetworkExclustionSettingUpdated += new NetworkEntityExcludeSetting.OnNetworkExclustionSettingUpdated(exSetting_NetworkExclustionSettingUpdated);
                PopupWindow dialog = new PopupWindow();
                dialog.Content = exSetting;
                dialog.Show();
            }
        }

        void exSetting_NetworkExclustionSettingUpdated(NetworkExclusionSetting exSetting)
        {
            this.radialGraph.ExSetting = exSetting;
            this.radialGraph.StartSimulation();
        }

        private void mnuInclude_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                NetworkEntitySelectSetting inSetting = new NetworkEntitySelectSetting(this.radialGraph.NetworkName);
                inSetting.NetworkInclustionSettingUpdated += new NetworkEntitySelectSetting.OnNetworkInclustionSettingUpdated(inSetting_NetworkInclustionSettingUpdated);
                PopupWindow dialog = new PopupWindow();
                dialog.Content = inSetting;
                dialog.Show();
            }
        }

        void inSetting_NetworkInclustionSettingUpdated(NetworkInclusionSetting inSetting)
        {
            this.radialGraph.InSetting = inSetting;
            this.radialGraph.StartSimulation();
        }
        #endregion

        #region dedup
        private void mnuDedup_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                NetworkDedupEditor netDedupEditor = new NetworkDedupEditor(this.radialGraph.NetworkName);
                netDedupEditor.NetworkDedupSettingUpdated += new NetworkDedupEditor.OnNetworkDedupSettingUpdated(netDedupEditor_NetworkDedupSettingUpdated);
                PopupWindow dialog = new PopupWindow();
                dialog.Content = netDedupEditor;
                dialog.Show();
            }
        }

        void netDedupEditor_NetworkDedupSettingUpdated(
            NetworkDedupSetting networkDedupSetting)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                NetworkDedupWorker dedupWorker = new NetworkDedupWorker(
                    this.radialGraph.NetworkName);
                Network network = dedupWorker.DedupNetwork();
                network.Save();
                this.UpdateNetworkGraph(network);
            }
        }

        #endregion

        #region explore
        private void cmu_ExplorePublications_Click(object sender, RoutedEventArgs e)
        {
            EntityType tgtEntityType = EntityType.Publications;
            this.ExplorRelations(tgtEntityType);
        }

        private void cmu_ExploreOrganizations_Click(object sender, RoutedEventArgs e)
        {
            EntityType tgtEntityType = EntityType.Organizations;
            this.ExplorRelations(tgtEntityType);
        }

        private void cmu_ExplorePersons_Click(object sender, RoutedEventArgs e)
        {
            EntityType tgtEntityType = EntityType.Persons;
            this.ExplorRelations(tgtEntityType);
        }

        private void cmu_ExploreGrants_Click(object sender, RoutedEventArgs e)
        {
            EntityType tgtEntityType = EntityType.Grants;
            this.ExplorRelations(tgtEntityType);
        }

        private void ExplorRelations(EntityType tgtEntityType)
        {
            if (!string.IsNullOrEmpty(this.radialGraph.NetworkName))
            {
                Network network = Network.Read(this.radialGraph.NetworkName);
                ExploreNetworkAssociation explorer =
                    new ExploreNetworkAssociation(network, RuleType.Link, tgtEntityType);
                explorer.NetworkUpdated += new ExploreNetworkAssociation.OnNetworkUpdated(UpdateNetworkGraph);
                PopupWindow dialog = new PopupWindow();
                dialog.Content = explorer;
                dialog.Show();
            }
        }
        #endregion

        
    }
}
